package kz.edu.sdu.itech.pcs.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

import kz.edu.sdu.itech.pcs.common.Client;
import kz.edu.sdu.itech.pcs.common.Message;
import kz.edu.sdu.itech.pcs.common.MessageType;

import org.apache.log4j.Logger;

public class Worker extends Client implements Runnable {

   static String OK = "OK";
   static Logger log = Logger.getLogger(Worker.class);

   Socket socket;
   Scanner in;
   PrintWriter out;
   Server server;
   Thread thread;
   boolean FINISH = false;

   String ip;

   public Worker(Socket socket, Server server) {
      this.socket = socket;
      this.server = server;
      try {
         in = new Scanner(socket.getInputStream());
         out = new PrintWriter(socket.getOutputStream());
         ip = socket.getInetAddress().getHostAddress();
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         server.getWorkerSet().add(this);
         thread = new Thread(this);
      }
   }

   public void close() {
      try {
         in.close();
         out.close();
         socket.close();
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         server.getWorkerSet().remove(this);
      }

   }

   public Thread getThread() {
      return thread;
   }

   public void setThread(Thread thread) {
      this.thread = thread;
   }

   public void say(MessageType mt) {
      Message m = new Message();
      m.setType(mt);
      say(m);
   }

   public String getIp() {
      return ip;
   }

   public String getSomeName() {
      if (title == null) {
         return ip;
      } else {
         return title;
      }
   }

   public void say(Message m) {
      out.println(m.toString());
      out.flush();
      if (AppProps.DEBUG)
         log.debug(String.format("say to %s: %s", getSomeName(), m.toString()));
   }

   public MessageFromWorker readResponse() {
      MessageFromWorker m = new MessageFromWorker(this);
      if (m.read())
         return m;
      return null;
   }

   public void handleResponse(MessageFromWorker res) {
      if (res == null) {
         log.debug(String.format("no connection with %s", getSomeName()));
         FINISH = true;
         return;
      }
      if (res.getType().equals(MessageType.HI)) {
         String n = res.getArgs().get("NAME");
         title = n;
      } else if (res.getType().equals(MessageType.START)) {
         String n = res.getArgs().get("msg");
         if (n.equals(OK)) {
            status = WORKING;
         }
      } else if (res.getType().equals(MessageType.STOP)) {
         String n = res.getArgs().get("msg");
         if (n.equals(OK)) {
            status = STOPED;
         }
      } else if (res.getType().equals(MessageType.COND)) {
         String n = res.getArgs().get("STATUS");
         status = n;
         if (!n.equals(NOT_STARTED)) {
            String cur = res.getArgs().get("CURRENT");
            String cnt = res.getArgs().get("COUNT");

            try {
               current = Long.valueOf(cur);
               count = Integer.valueOf(cnt);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      } else if (res.getType().equals(MessageType.BYE)) {
//         STOPED = true;
      }
   }

   public synchronized void speak(MessageType mt) {
      Message m = new Message();
      m.setType(mt);
      speak(m);
   }

   public void startWork() {
      Message m = new Message();
      m.setType(MessageType.START);
      m.addArg("alphabet", alphabet.toString());
      m.addArg("len", "" + len);
      m.addArg("start", "" + start);
      m.addArg("end", "" + end);
      m.addArg("hash", "" + hash);
      speak(m);
   }

   public void stopWork() {
      speak(MessageType.STOP);
   }

   public synchronized void speak(Message m) {
      say(m);
      MessageFromWorker res = readResponse();
      handleResponse(res);
   }

   @Override
   public void run() {
      speak(MessageType.HI);
      while (!FINISH && !AppProps.DONE) {
         speak(MessageType.COND);
         sleep(2000);
      }
      speak(MessageType.BYE);
      close();
   }

   public static void sleep(int x) {
      try {
         Thread.sleep(x);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

//   @Override
//   public String toString() {
//      return String.format("ip=%s, name=%s, status=%s, [%.2f]", ip, title, status, getPercentage());
//   }
}
